home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / sparcmgr / demo2.zoo / demo / ex / ex_put.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-04-24  |  20.9 KB  |  1,175 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. static char *sccsid = "@(#)ex_put.c    7.10 (Berkeley) 3/9/87; 1.2 (Bellcore)    87/04/24";
  9. #endif not lint
  10.  
  11. #include "ex.h"
  12. #include "ex_tty.h"
  13. #include "ex_vis.h"
  14.  
  15. /*
  16.  * Terminal driving and line formatting routines.
  17.  * Basic motion optimizations are done here as well
  18.  * as formatting of lines (printing of control characters,
  19.  * line numbering and the like).
  20.  */
  21.  
  22. /*
  23.  * The routines outchar, putchar and pline are actually
  24.  * variables, and these variables point at the current definitions
  25.  * of the routines.  See the routine setflav.
  26.  * We sometimes make outchar be routines which catch the characters
  27.  * to be printed, e.g. if we want to see how long a line is.
  28.  * During open/visual, outchar and putchar will be set to
  29.  * routines in the file ex_vput.c (vputchar, vinschar, etc.).
  30.  */
  31. int    (*Outchar)() = termchar;
  32. int    (*Put_char)() = normchar;
  33. int    (*Pline)() = normline;
  34.  
  35. int (*
  36. setlist(t))()
  37.     bool t;
  38. {
  39.     register int (*P)();
  40.  
  41.     listf = t;
  42.     P = Put_char;
  43.     Put_char = t ? listchar : normchar;
  44.     return (P);
  45. }
  46.  
  47. int (*
  48. setnumb(t))()
  49.     bool t;
  50. {
  51.     register int (*P)();
  52.  
  53.     numberf = t;
  54.     P = Pline;
  55.     Pline = t ? numbline : normline;
  56.     return (P);
  57. }
  58.  
  59. /*
  60.  * Format c for list mode; leave things in common
  61.  * with normal print mode to be done by normchar.
  62.  */
  63. listchar(c)
  64.     register short c;
  65. {
  66.  
  67.     c &= (TRIM|QUOTE);
  68.     switch (c) {
  69.  
  70.     case '\t':
  71.     case '\b':
  72.         outchar('^');
  73.         c = ctlof(c);
  74.         break;
  75.  
  76.     case '\n':
  77.         break;
  78.  
  79.     case '\n' | QUOTE:
  80.         outchar('$');
  81.         break;
  82.  
  83.     default:
  84.         if (c & QUOTE)
  85.             break;
  86.         if (c < ' ' && c != '\n' || c == DELETE)
  87.             outchar('^'), c = ctlof(c);
  88.         break;
  89.     }
  90.     normchar(c);
  91. }
  92.  
  93. /*
  94.  * Format c for printing.  Handle funnies of upper case terminals
  95.  * and crocky hazeltines which don't have ~.
  96.  */
  97. normchar(c)
  98.     register short c;
  99. {
  100.     register char *colp;
  101.  
  102.     c &= (TRIM|QUOTE);
  103.     if (c == '~' && HZ) {
  104.         normchar('\\');
  105.         c = '^';
  106.     }
  107.     if (c & QUOTE)
  108.         switch (c) {
  109.  
  110.         case ' ' | QUOTE:
  111.         case '\b' | QUOTE:
  112.             break;
  113.  
  114.         case QUOTE:
  115.             return;
  116.  
  117.         default:
  118.             c &= TRIM;
  119.         }
  120.     else if (c < ' ' && (c != '\b' || !OS) && c != '\n' && c != '\t' || c == DELETE)
  121.         ex_putchar('^'), c = ctlof(c);
  122.     else if (UPPERCASE)
  123.         if (isupper(c)) {
  124.             outchar('\\');
  125.             c = tolower(c);
  126.         } else {
  127.             colp = "({)}!|^~'`";
  128.             while (*colp++)
  129.                 if (c == *colp++) {
  130.                     outchar('\\');
  131.                     c = colp[-2];
  132.                     break;
  133.                 }
  134.         }
  135.     outchar(c);
  136. }
  137.  
  138. /*
  139.  * Print a line with a number.
  140.  */
  141. numbline(i)
  142.     int i;
  143. {
  144.  
  145.     if (shudclob)
  146.         slobber(' ');
  147.     ex_printf("%6d  ", i);
  148.     normline();
  149. }
  150.  
  151. /*
  152.  * Normal line output, no numbering.
  153.  */
  154. normline()
  155. {
  156.     register char *cp;
  157.  
  158.     if (shudclob)
  159.         slobber(linebuf[0]);
  160.     /* pdp-11 doprnt is not reentrant so can't use "printf" here
  161.        in case we are tracing */
  162.     for (cp = linebuf; *cp;)
  163.         ex_putchar(*cp++);
  164.     if (!inopen)
  165.         ex_putchar('\n' | QUOTE);
  166. }
  167.  
  168. /*
  169.  * Given c at the beginning of a line, determine whether
  170.  * the printing of the line will erase or otherwise obliterate
  171.  * the prompt which was printed before.  If it won't, do it now.
  172.  */
  173. slobber(c)
  174.     int c;
  175. {
  176.  
  177.     shudclob = 0;
  178.     switch (c) {
  179.  
  180.     case '\t':
  181.         if (Put_char == listchar)
  182.             return;
  183.         break;
  184.  
  185.     default:
  186.         return;
  187.  
  188.     case ' ':
  189.     case 0:
  190.         break;
  191.     }
  192.     if (OS)
  193.         return;
  194.     flush();
  195.     putch(' ');
  196.     if (BC)
  197.         tputs(BC, 0, putch);
  198.     else
  199.         putch('\b');
  200. }
  201.  
  202. /*
  203.  * The output buffer is initialized with a useful error
  204.  * message so we don't have to keep it in data space.
  205.  */
  206. static    char linb[66];
  207. char *linp = linb;
  208.  
  209. /*
  210.  * Phadnl records when we have already had a complete line ending with \n.
  211.  * If another line starts without a flush, and the terminal suggests it,
  212.  * we switch into -nl mode so that we can send lineffeeds to avoid
  213.  * a lot of spacing.
  214.  */
  215. static    bool phadnl;
  216.  
  217. /*
  218.  * Indirect to current definition of putchar.
  219.  */
  220. ex_putchar(c)
  221.     int c;
  222. {
  223.  
  224.     (*Put_char)(c);
  225. }
  226.  
  227. /*
  228.  * Termchar routine for command mode.
  229.  * Watch for possible switching to -nl mode.
  230.  * Otherwise flush into next level of buffering when
  231.  * small buffer fills or at a newline.
  232.  */
  233. termchar(c)
  234.     int c;
  235. {
  236.  
  237.     if (pfast == 0 && phadnl)
  238.         pstart();
  239.     if (c == '\n')
  240.         phadnl = 1;
  241.     else if (linp >= &linb[63])
  242.         flush1();
  243.     *linp++ = c;
  244.     if (linp >= &linb[63]) {
  245.         fgoto();
  246.         flush1();
  247.     }
  248. }
  249.  
  250. flush()
  251. {
  252.  
  253.     flush1();
  254.     flush2();
  255. }
  256.  
  257. /*
  258.  * Flush from small line buffer into output buffer.
  259.  * Work here is destroying motion into positions, and then
  260.  * letting fgoto do the optimized motion.
  261.  */
  262. flush1()
  263. {
  264.     register char *lp;
  265.     register short c;
  266.  
  267.     *linp = 0;
  268.     lp = linb;
  269.     while (*lp)
  270.         switch (c = *lp++) {
  271.  
  272.         case '\r':
  273.             destline += destcol / COLUMNS;
  274.             destcol = 0;
  275.             continue;
  276.  
  277.         case '\b':
  278.             if (destcol)
  279.                 destcol--;
  280.             continue;
  281.  
  282.         case ' ':
  283.             destcol++;
  284.             continue;
  285.  
  286.         case '\t':
  287.             destcol += value(TABSTOP) - destcol % value(TABSTOP);
  288.             continue;
  289.  
  290.         case '\n':
  291.             destline += destcol / COLUMNS + 1;
  292.             if (destcol != 0 && destcol % COLUMNS == 0)
  293.                 destline--;
  294.             destcol = 0;
  295.             continue;
  296.  
  297.         default:
  298.             fgoto();
  299.             for (;;) {
  300.                 if (AM == 0 && outcol == COLUMNS)
  301.                     fgoto();
  302.                 c &= TRIM;
  303.                 putch(c);
  304.                 if (c == '\b') {
  305.                     outcol--;
  306.                     destcol--;
  307.                 } else if (c >= ' ' && c != DELETE) {
  308.                     outcol++;
  309.                     destcol++;
  310.                     if (XN && outcol % COLUMNS == 0)
  311.                         putch('\r'), putch('\n');
  312.                 }
  313.                 c = *lp++;
  314.                 if (c <= ' ')
  315.                     break;
  316.             }
  317.             --lp;
  318.             continue;
  319.         }
  320.     linp = linb;
  321. }
  322.  
  323. flush2()
  324. {
  325.  
  326.     fgoto();
  327.     flusho();
  328.     pstop();
  329. }
  330.  
  331. /*
  332.  * Sync the position of the output cursor.
  333.  * Most work here is rounding for terminal boundaries getting the
  334.  * column position implied by wraparound or the lack thereof and
  335.  * rolling up the screen to get destline on the screen.
  336.  */
  337. fgoto()
  338. {
  339.     register int l, c;
  340.  
  341.     if (destcol > COLUMNS - 1) {
  342.         destline += destcol / COLUMNS;
  343.         destcol %= COLUMNS;
  344.     }
  345.     if (outcol > COLUMNS - 1) {
  346.         l = (outcol + 1) / COLUMNS;
  347.         outline += l;
  348.         outcol %= COLUMNS;
  349.         if (AM == 0) {
  350.             while (l > 0) {
  351.                 if (pfast)
  352.                     if (xCR)
  353.                         tputs(xCR, 0, putch);
  354.                     else
  355.                         putch('\r');
  356.                 if (xNL)
  357.                     tputs(xNL, 0, putch);
  358.                 else
  359.                     putch('\n');
  360.                 l--;
  361.             }
  362.             outcol = 0;
  363.         }
  364.         if (outline > LINES - 1) {
  365.             destline -= outline - (LINES - 1);
  366.             outline = LINES - 1;
  367.         }
  368.     }
  369.     if (destline > LINES - 1) {
  370.         l = destline;
  371.         destline = LINES - 1;
  372.         if (outline < LINES - 1) {
  373.             c = destcol;
  374.             if (pfast == 0 && (!CA || holdcm))
  375.                 destcol = 0;
  376.             fgoto();
  377.             destcol = c;
  378.         }
  379.         while (l > LINES - 1) {
  380.             /*
  381.              * The following linefeed (or simulation thereof)
  382.              * is supposed to scroll up the screen, since we
  383.              * are on the bottom line.  We make the assumption
  384.              * that linefeed will scroll.  If ns is in the
  385.              * capability list this won't work.  We should
  386.              * probably have an sc capability but sf will
  387.              * generally take the place if it works.
  388.              *
  389.              * Superbee glitch:  in the middle of the screen we
  390.              * have to use esc B (down) because linefeed screws up
  391.              * in "Efficient Paging" (what a joke) mode (which is
  392.              * essential in some SB's because CRLF mode puts garbage
  393.              * in at end of memory), but you must use linefeed to
  394.              * scroll since down arrow won't go past memory end.
  395.              * I turned this off after recieving Paul Eggert's
  396.              * Superbee description which wins better.
  397.              */
  398.             if (xNL /* && !XB */ && pfast)
  399.                 tputs(xNL, 0, putch);
  400.             else
  401.                 putch('\n');
  402.             l--;
  403.             if (pfast == 0)
  404.                 outcol = 0;
  405.         }
  406.     }
  407.     if (destline < outline && !(CA && !holdcm || UP != NOSTR))
  408.         destline = outline;
  409.     if (CA && !holdcm)
  410.         if (plod(costCM) > 0)
  411.             plod(0);
  412.         else
  413.             tputs(tgoto(CM, destcol, destline), 0, putch);
  414.     else
  415.         plod(0);
  416.     outline = destline;
  417.     outcol = destcol;
  418. }
  419.  
  420. /*
  421.  * Tab to column col by flushing and then setting destcol.
  422.  * Used by "set all".
  423.  */
  424. tab(col)
  425.     int col;
  426. {
  427.  
  428.     flush1();
  429.     destcol = col;
  430. }
  431.  
  432. /*
  433.  * Move (slowly) to destination.
  434.  * Hard thing here is using home cursor on really deficient terminals.
  435.  * Otherwise just use cursor motions, hacking use of tabs and overtabbing
  436.  * and backspace.
  437.  */
  438.  
  439. static int plodcnt, plodflg;
  440.  
  441. plodput(c)
  442. {
  443.  
  444.     if (plodflg)
  445.         plodcnt--;
  446.     else
  447.         putch(c);
  448. }
  449.  
  450. plod(cnt)
  451. {
  452.     register int i, j, k;
  453.     register int soutcol, soutline;
  454.  
  455.     plodcnt = plodflg = cnt;
  456.     soutcol = outcol;
  457.     soutline = outline;
  458.     /*
  459.      * Consider homing and moving down/right from there, vs moving
  460.      * directly with local motions to the right spot.
  461.      */
  462.     if (HO) {
  463.         /*
  464.          * i is the cost to home and tab/space to the right to
  465.          * get to the proper column.  This assumes ND space costs
  466.          * 1 char.  So i+destcol is cost of motion with home.
  467.          */
  468.         if (GT)
  469.             i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS));
  470.         else
  471.             i = destcol;
  472.         /*
  473.          * j is cost to move locally without homing
  474.          */
  475.         if (destcol >= outcol) {    /* if motion is to the right */
  476.             j = destcol / value(HARDTABS) - outcol / value(HARDTABS);
  477.             if (GT && j)
  478.                 j += destcol % value(HARDTABS);
  479.             else
  480.                 j = destcol - outcol;
  481.         } else
  482.             /* leftward motion only works if we can backspace. */
  483.             if (outcol - destcol <= i && (BS || BC))
  484.                 i = j = outcol - destcol; /* cheaper to backspace */
  485.             else
  486.                 j = i + 1; /* impossibly expensive */
  487.  
  488.         /* k is the absolute value of vertical distance */
  489.         k = outline - destline;
  490.         if (k < 0)
  491.             k = -k;
  492.         j += k;
  493.  
  494.         /*
  495.          * Decision.  We may not have a choice if no UP.
  496.          */
  497.         if (i + destline < j || (!UP && destline < outline)) {
  498.             /*
  499.              * Cheaper to home.  Do it now and pretend it's a
  500.              * regular local motion.
  501.              */
  502.             tputs(HO, 0, plodput);
  503.             outcol = outline = 0;
  504.         } else if (LL) {
  505.             /*
  506.              * Quickly consider homing down and moving from there.
  507.              * Assume cost of LL is 2.
  508.              */
  509.             k = (LINES - 1) - destline;
  510.             if (i + k + 2 < j && (k<=0 || UP)) {
  511.                 tputs(LL, 0, plodput);
  512.                 outcol = 0;
  513.                 outline = LINES - 1;
  514.             }
  515.         }
  516.     } else
  517.     /*
  518.      * No home and no up means it's impossible, so we return an
  519.      * incredibly big number to make cursor motion win out.
  520.      */
  521.         if (!UP && destline < outline)
  522.             return (500);
  523.     if (GT)
  524.         i = destcol % value(HARDTABS)
  525.             + destcol / value(HARDTABS);
  526.     else
  527.         i = destcol;
  528. /*
  529.     if (BT && outcol > destcol && (j = (((outcol+7) & ~7) - destcol - 1) >> 3)) {
  530.         j *= (k = strlen(BT));
  531.         if ((k += (destcol&7)) > 4)
  532.             j += 8 - (destcol&7);
  533.         else
  534.             j += k;
  535.     } else
  536. */
  537.         j = outcol - destcol;
  538.     /*
  539.      * If we will later need a \n which will turn into a \r\n by
  540.      * the system or the terminal, then don't bother to try to \r.
  541.      */
  542.     if ((NONL || !pfast) && outline < destline)
  543.         goto dontcr;
  544.     /*
  545.      * If the terminal will do a \r\n and there isn't room for it,
  546.      * then we can't afford a \r.
  547.      */
  548.     if (NC && outline >= destline)
  549.         goto dontcr;
  550.     /*
  551.      * If it will be cheaper, or if we can't back up, then send
  552.      * a return preliminarily.
  553.      */
  554.     if (j > i + 1 || outcol > destcol && !BS && !BC) {
  555.         /*
  556.          * BUG: this doesn't take the (possibly long) length
  557.          * of xCR into account.
  558.          */
  559.         if (xCR)
  560.             tputs(xCR, 0, plodput);
  561.         else
  562.             plodput('\r');
  563.         if (NC) {
  564.             if (xNL)
  565.                 tputs(xNL, 0, plodput);
  566.             else
  567.                 plodput('\n');
  568.             outline++;
  569.         }
  570.         outcol = 0;
  571.     }
  572. dontcr:
  573.     /* Move down, if necessary, until we are at the desired line */
  574.     while (outline < destline) {
  575.         j = destline - outline;
  576.         if (j > costDP && DOWN_PARM) {
  577.             /* Win big on Tek 4025 */
  578.             tputs(tgoto(DOWN_PARM, 0, j), j, plodput);
  579.             outline += j;
  580.         }
  581.         else {
  582.             outline++;
  583.             if (xNL && pfast)
  584.                 tputs(xNL, 0, plodput);
  585.             else
  586.                 plodput('\n');
  587.         }
  588.         if (plodcnt < 0)
  589.             goto out;
  590.         if (NONL || pfast == 0)
  591.             outcol = 0;
  592.     }
  593.     if (BT)
  594.         k = strlen(BT);    /* should probably be cost(BT) and moved out */
  595.     /* Move left, if necessary, to desired column */
  596.     while (outcol > destcol) {
  597.         if (plodcnt < 0)
  598.             goto out;
  599.         if (BT && !insmode && outcol - destcol > 4+k) {
  600.             tputs(BT, 0, plodput);
  601.             outcol--;
  602.             outcol -= outcol % value(HARDTABS); /* outcol &= ~7; */
  603.             continue;
  604.         }
  605.         j = outcol - destcol;
  606.         if (j > costLP && LEFT_PARM) {
  607.             tputs(tgoto(LEFT_PARM, 0, j), j, plodput);
  608.             outcol -= j;
  609.         }
  610.         else {
  611.             outcol--;
  612.             if (BC)
  613.                 tputs(BC, 0, plodput);
  614.             else
  615.                 plodput('\b');
  616.         }
  617.     }
  618.     /* Move up, if necessary, to desired row */
  619.     while (outline > destline) {
  620.         j = outline - destline;
  621.         if (UP_PARM && j > 1) {
  622.             /* Win big on Tek 4025 */
  623.             tputs(tgoto(UP_PARM, 0, j), j, plodput);
  624.             outline -= j;
  625.         }
  626.         else {
  627.             outline--;
  628.             tputs(UP, 0, plodput);
  629.         }
  630.         if (plodcnt < 0)
  631.             goto out;
  632.     }
  633.     /*
  634.      * Now move to the right, if necessary.  We first tab to
  635.      * as close as we can get.
  636.      */
  637.     if (GT && !insmode && destcol - outcol > 1) {
  638.         /* tab to right as far as possible without passing col */
  639.         for (;;) {
  640.             i = tabcol(outcol, value(HARDTABS));
  641.             if (i > destcol)
  642.                 break;
  643.             if (TA)
  644.                 tputs(TA, 0, plodput);
  645.             else
  646.                 plodput('\t');
  647.             outcol = i;
  648.         }
  649.         /* consider another tab and then some backspaces */
  650.         if (destcol - outcol > 4 && i < COLUMNS && (BC || BS)) {
  651.             if (TA)
  652.                 tputs(TA, 0, plodput);
  653.             else
  654.                 plodput('\t');
  655.             outcol = i;
  656.             /*
  657.              * Back up.  Don't worry about LEFT_PARM because
  658.              * it's never more than 4 spaces anyway.
  659.              */
  660.             while (outcol > destcol) {
  661.                 outcol--;
  662.                 if (BC)
  663.                     tputs(BC, 0, plodput);
  664.                 else
  665.                     plodput('\b');
  666.             }
  667.         }
  668.     }
  669.     /*
  670.      * We've tabbed as much as possible.  If we still need to go
  671.      * further (not exact or can't tab) space over.  This is a
  672.      * very common case when moving to the right with space.
  673.      */
  674.     while (outcol < destcol) {
  675.         j = destcol - outcol;
  676.         if (j > costRP && RIGHT_PARM) {
  677.             /*
  678.              * This probably happens rarely, if at all.
  679.              * It seems mainly useful for ANSI terminals
  680.              * with no hardware tabs, and I don't know
  681.              * of any such terminal at the moment.
  682.              */
  683.             tputs(tgoto(RIGHT_PARM, 0, j), j, plodput);
  684.             outcol += j;
  685.         }
  686.         else {
  687.             /*
  688.              * move one char to the right.  We don't use ND space
  689.              * because it's better to just print the char we are
  690.              * moving over.  There are various exceptions, however.
  691.              * If !inopen, vtube contains garbage.  If the char is
  692.              * a null or a tab we want to print a space.  Other
  693.              * random chars we use space for instead, too.
  694.              */
  695.             if (!inopen || vtube[outline]==NULL ||
  696.                 (i=vtube[outline][outcol]) < ' ')
  697.                 i = ' ';
  698.             if(i & QUOTE)    /* mjm: no sign extension on 3B */
  699.                 i = ' ';
  700.             if (insmode && ND)
  701.                 tputs(ND, 0, plodput);
  702.             else
  703.                 plodput(i);
  704.             outcol++;
  705.         }
  706.         if (plodcnt < 0)
  707.             goto out;
  708.     }
  709. out:
  710.     if (plodflg) {
  711.         outcol = soutcol;
  712.         outline = soutline;
  713.     }
  714.     return(plodcnt);
  715. }
  716.  
  717. /*
  718.  * An input line arrived.
  719.  * Calculate new (approximate) screen line position.
  720.  * Approximate because kill character echoes newline with
  721.  * no feedback and also because of long input lines.
  722.  */
  723. noteinp()
  724. {
  725.  
  726.     outline++;
  727.     if (outline > LINES - 1)
  728.         outline = LINES - 1;
  729.     destline = outline;
  730.     destcol = outcol = 0;
  731. }
  732.  
  733. /*
  734.  * Something weird just happened and we
  735.  * lost track of whats happening out there.
  736.  * Since we cant, in general, read where we are
  737.  * we just reset to some known state.
  738.  * On cursor addressible terminals setting to unknown
  739.  * will force a cursor address soon.
  740.  */
  741. termreset()
  742. {
  743.  
  744.     endim();
  745.     if (TI)    /* otherwise it flushes anyway, and 'set tty=dumb' vomits */
  746.         putpad(TI);     /*adb change -- emit terminal initial sequence */
  747.     destcol = 0;
  748.     destline = LINES - 1;
  749.     if (CA) {
  750.         outcol = UKCOL;
  751.         outline = UKCOL;
  752.     } else {
  753.         outcol = destcol;
  754.         outline = destline;
  755.     }
  756. }
  757.  
  758. /*
  759.  * Low level buffering, with the ability to drain
  760.  * buffered output without printing it.
  761.  */
  762. char    *obp = obuf;
  763.  
  764. draino()
  765. {
  766.  
  767.     obp = obuf;
  768. }
  769.  
  770. flusho()
  771. {
  772.  
  773.     if (obp != obuf) {
  774. #ifndef vms
  775.         write(1, obuf, obp - obuf);
  776. #else
  777.         vms_write(1, obuf, obp - obuf);
  778. #endif
  779.         obp = obuf;
  780.     }
  781. }
  782.  
  783. putnl()
  784. {
  785.  
  786.     ex_putchar('\n');
  787. }
  788.  
  789. ex_putS(cp)
  790.     char *cp;
  791. {
  792.  
  793.     if (cp == NULL)
  794.         return;
  795.     while (*cp)
  796.         putch(*cp++);
  797. }
  798.  
  799.  
  800. putch(c)
  801.     int c;
  802. {
  803.  
  804. #ifdef OLD3BTTY        /* mjm */
  805.     if(c == '\n')    /* mjm: Fake "\n\r" for '\n' til fix in 3B firmware */
  806.         putch('\r');    /* mjm: vi does "stty -icanon" => -onlcr !! */
  807. #endif
  808.     *obp++ = c & 0177;
  809.     if (obp >= &obuf[sizeof obuf])
  810.         flusho();
  811. }
  812.  
  813. /*
  814.  * Miscellaneous routines related to output.
  815.  */
  816.  
  817. /*
  818.  * Put with padding
  819.  */
  820. putpad(cp)
  821.     char *cp;
  822. {
  823.  
  824.     flush();
  825.     tputs(cp, 0, putch);
  826. }
  827.  
  828. /*
  829.  * Set output through normal command mode routine.
  830.  */
  831. setoutt()
  832. {
  833.  
  834.     Outchar = termchar;
  835. }
  836.  
  837. /*
  838.  * Printf (temporarily) in list mode.
  839.  */
  840. /*VARARGS1*/
  841. lprintf(cp, dp)
  842.     char *cp, *dp;
  843. {
  844.     register int (*P)();
  845.  
  846.     P = setlist(1);
  847.     ex_printf(cp, dp);
  848.     Put_char = P;
  849. }
  850.  
  851. /*
  852.  * Newline + flush.
  853.  */
  854. putNFL()
  855. {
  856.  
  857.     putnl();
  858.     flush();
  859. }
  860.  
  861. /*
  862.  * Try to start -nl mode.
  863.  */
  864. pstart()
  865. {
  866.  
  867.     if (NONL)
  868.         return;
  869.      if (!value(OPTIMIZE))
  870.         return;
  871.     if (ruptible == 0 || pfast)
  872.         return;
  873.     fgoto();
  874.     flusho();
  875.     pfast = 1;
  876.     normtty++;
  877. #ifndef USG3TTY
  878.     tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD);
  879. #else
  880.     tty = normf;
  881.     tty.c_oflag &= ~(ONLCR|TAB3);
  882.     tty.c_lflag &= ~ECHO;
  883. #endif
  884.     ex_sTTY(1);
  885. }
  886.  
  887. /*
  888.  * Stop -nl mode.
  889.  */
  890. pstop()
  891. {
  892.  
  893.     if (inopen)
  894.         return;
  895.     phadnl = 0;
  896.     linp = linb;
  897.     draino();
  898.     normal(normf);
  899.     pfast &= ~1;
  900. }
  901.  
  902. /*
  903.  * Prep tty for open mode.
  904.  */
  905. ttymode
  906. ostart()
  907. {
  908.     ttymode f;
  909.  
  910.     if (!intty)
  911.         error("Open and visual must be used interactively");
  912.     ex_gTTY(1);
  913.     normtty++;
  914. #ifndef USG3TTY
  915.     f = tty.sg_flags;
  916.     tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) |
  917. # ifdef CBREAK
  918.                             CBREAK;
  919. # else
  920.                             RAW;
  921. # endif
  922. # ifdef TIOCGETC
  923.     ttcharoff();
  924. # endif
  925. #else
  926.     f = tty;
  927.     tty = normf;
  928.     tty.c_iflag &= ~ICRNL;
  929.     tty.c_lflag &= ~(ECHO|ICANON);
  930.     tty.c_oflag &= ~(TAB3|ONLCR);
  931.     tty.c_cc[VMIN] = 1;
  932.     tty.c_cc[VTIME] = 1;
  933.     ttcharoff();
  934. #endif
  935.     ex_sTTY(1);
  936.     tostart();
  937.     pfast |= 2;
  938.     return (f);
  939. }
  940.  
  941. /* actions associated with putting the terminal in open mode */
  942. tostart()
  943. {
  944.     putpad(VS);
  945.     putpad(KS);
  946.     if (!value(MESG)) {
  947.         if (ttynbuf[0] == 0) {
  948.             register char *tn;
  949.             if ((tn=ttyname(2)) == NULL &&
  950.                 (tn=ttyname(1)) == NULL &&
  951.                 (tn=ttyname(0)) == NULL)
  952.                 ttynbuf[0] = 1;
  953.             else
  954.                 strcpy(ttynbuf, tn);
  955.         }
  956.         if (ttynbuf[0] != 1) {
  957.             struct stat sbuf;
  958.             stat(ttynbuf, &sbuf);
  959.             ttymesg = sbuf.st_mode & 0777;
  960.             chmod(ttynbuf,
  961. #ifdef UCBV7
  962.     /*
  963.      * This applies to the UCB V7 Pdp-11 system with the
  964.      * -u write option only.
  965.      */
  966.                     0611    /* 11 = urgent only allowed */
  967. #else
  968.                     0600
  969. #endif
  970.                         );
  971.         }
  972.     }
  973. }
  974.  
  975. /*
  976.  * Turn off start/stop chars if they aren't the default ^S/^Q.
  977.  * This is so idiots who make esc their start/stop don't lose.
  978.  * We always turn off quit since datamedias send ^\ for their
  979.  * right arrow key.
  980.  */
  981. #ifdef TIOCGETC
  982. ttcharoff()
  983. {
  984.     nttyc.t_quitc = '\377';
  985.     if (nttyc.t_startc != CTRL(q))
  986.         nttyc.t_startc = '\377';
  987.     if (nttyc.t_stopc != CTRL(s))
  988.         nttyc.t_stopc = '\377';
  989. # ifdef TIOCLGET
  990.     nlttyc.t_suspc = '\377';    /* ^Z */
  991.     nlttyc.t_dsuspc = '\377';    /* ^Y */
  992.     nlttyc.t_flushc = '\377';    /* ^O */
  993.     nlttyc.t_lnextc = '\377';    /* ^V */
  994. # endif
  995. }
  996. #endif
  997.  
  998. #ifdef USG3TTY
  999. ttcharoff()
  1000. {
  1001.     tty.c_cc[VQUIT] = '\377';
  1002. # ifdef VSTART
  1003.     /*
  1004.      * The following is sample code if USG ever lets people change
  1005.      * their start/stop chars.  As long as they can't we can't get
  1006.      * into trouble so we just leave them alone.
  1007.      */
  1008.     if (tty.c_cc[VSTART] != CTRL(q))
  1009.         tty.c_cc[VSTART] = '\377';
  1010.     if (tty.c_cc[VSTOP] != CTRL(s))
  1011.         tty.c_cc[VSTOP] = '\377';
  1012. # endif
  1013. }
  1014. #endif
  1015.  
  1016. /*
  1017.  * Stop open, restoring tty modes.
  1018.  */
  1019. ostop(f)
  1020.     ttymode f;
  1021. {
  1022.  
  1023. #ifndef USG3TTY
  1024.     pfast = (f & CRMOD) == 0;
  1025. #else
  1026.     pfast = (f.c_oflag & ONLCR) == 0;
  1027. #endif
  1028.     termreset(), fgoto(), flusho();
  1029.     normal(f);
  1030.     tostop();
  1031. }
  1032.  
  1033. /* Actions associated with putting the terminal in the right mode. */
  1034. tostop()
  1035. {
  1036.     putpad(VE);
  1037.     putpad(KE);
  1038.     if (!value(MESG) && ttynbuf[0]>1)
  1039.         chmod(ttynbuf, ttymesg);
  1040. }
  1041.  
  1042. #ifndef CBREAK
  1043. /*
  1044.  * Into cooked mode for interruptibility.
  1045.  */
  1046. vcook()
  1047. {
  1048.  
  1049.     tty.sg_flags &= ~RAW;
  1050.     ex_sTTY(1);
  1051. }
  1052.  
  1053. /*
  1054.  * Back into raw mode.
  1055.  */
  1056. vraw()
  1057. {
  1058.  
  1059.     tty.sg_flags |= RAW;
  1060.     ex_sTTY(1);
  1061. }
  1062. #endif
  1063.  
  1064. /*
  1065.  * Restore flags to normal state f.
  1066.  */
  1067. normal(f)
  1068.     ttymode f;
  1069. {
  1070.  
  1071.     if (normtty > 0) {
  1072.         ignore(setty(f));
  1073.         normtty--;
  1074.     }
  1075. }
  1076.  
  1077. /*
  1078.  * Straight set of flags to state f.
  1079.  */
  1080. ttymode
  1081. setty(f)
  1082.     ttymode f;
  1083. {
  1084. #ifndef USG3TTY
  1085.     register int ot = tty.sg_flags;
  1086. #else
  1087.     ttymode ot;
  1088.     ot = tty;
  1089. #endif
  1090.  
  1091. #ifndef USG3TTY
  1092. # ifdef TIOCGETC
  1093.     if (f == normf) {
  1094.         nttyc = ottyc;
  1095. # ifdef TIOCLGET
  1096.         nlttyc = olttyc;
  1097. # endif
  1098.     } else
  1099.         ttcharoff();
  1100. # endif
  1101.     tty.sg_flags = f;
  1102. #else
  1103.     if (tty.c_lflag & ICANON)
  1104.         ttcharoff();
  1105.     tty = f;
  1106. #endif
  1107.     ex_sTTY(1);
  1108.     return (ot);
  1109. }
  1110.  
  1111. ex_gTTY(i)
  1112.     int i;
  1113. {
  1114.  
  1115. #ifndef USG3TTY
  1116.     ignore(gtty(i, &tty));
  1117. # ifdef TIOCGETC
  1118.     ioctl(i, TIOCGETC, (char *) &ottyc);
  1119.     nttyc = ottyc;
  1120. # endif
  1121. # ifdef TIOCGLTC
  1122.     ioctl(i, TIOCGLTC, (char *) &olttyc);
  1123.     nlttyc = olttyc;
  1124. # endif
  1125. #else
  1126.     ioctl(i, TCGETA, (char *) &tty);
  1127. #endif
  1128. }
  1129.  
  1130. /*
  1131.  * ex_sTTY: set the tty modes on file descriptor i to be what's
  1132.  * currently in global "tty".  (Also use nttyc if needed.)
  1133.  */
  1134. ex_sTTY(i)
  1135.     int i;
  1136. {
  1137.  
  1138. #ifndef USG3TTY
  1139. # ifdef USG
  1140.     /* Bug in USG tty driver, put out a DEL as a patch. */
  1141.     if (tty.sg_ospeed >= B1200)
  1142.         write(1, "\377", 1);
  1143. # endif
  1144.  
  1145. # ifdef TIOCSETN
  1146.     /* Don't flush typeahead if we don't have to */
  1147.     ioctl(i, TIOCSETN, (char *) &tty);
  1148. # else
  1149.     /* We have to.  Too bad. */
  1150.     stty(i, &tty);
  1151. # endif
  1152.  
  1153. # ifdef TIOCGETC
  1154.     /* Update the other random chars while we're at it. */
  1155.     ioctl(i, TIOCSETC, (char *) &nttyc);
  1156. # endif
  1157. # ifdef TIOCSLTC
  1158.     ioctl(i, TIOCSLTC, (char *) &nlttyc);
  1159. # endif
  1160.  
  1161. #else
  1162.     /* USG 3 very simple: just set everything */
  1163.     ioctl(i, TCSETAW, (char *) &tty);
  1164. #endif
  1165. }
  1166.  
  1167. /*
  1168.  * Print newline, or blank if in open/visual
  1169.  */
  1170. noonl()
  1171. {
  1172.  
  1173.     ex_putchar(Outchar != termchar ? ' ' : '\n');
  1174. }
  1175.